import { useEffect, useRef, useState } from 'react';

type Fn<T> = (state: T) => void;
type PreFn<T> = (state: T, nextState: T) => boolean;
export const useStateCallback = function <S>(
    initial: S | (() => S)
): [S, (nextState: S, nextCallBack?: Fn<S>, preCompare?: PreFn<S>) => void] {
    const [state, setState] = useState<S>(initial);
    const handleRef = useRef(new Set<Fn<S>>());

    const setUpdateRef = useRef((nextState: S, nextCallBack?: Fn<S>, preCompare?: PreFn<S>) => {
        if (typeof preCompare === 'function' && !preCompare(state, nextState)) {
            return;
        }
        if (typeof nextCallBack === 'function') {
            handleRef.current.add(nextCallBack);
        }

        return setState(nextState);
    });
    useEffect(() => {
        if (handleRef.current.size > 0) {
            handleRef.current.forEach((h: Fn<S>) => h(state));
            handleRef.current.clear();
        }
    }, [state]);

    return [state, setUpdateRef.current];
};
